#ifndef __MY_LOG_FORMAT__
#define __MY_LOG_FORMAT__
#include<vector>
#include<sstream>
#include<memory>
#include"message.hpp"
#include<cassert>
namespace mylog
{
    class FormatItem
    {
        public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual void Format(std::ostream& out, LogMsg& msg) = 0;
    };

    class MsgFormatItem : public FormatItem
    {
        public:
        void Format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._payload;
        }
    };
    class LevelFormatItem : public FormatItem
    {
        public:
        void Format(std::ostream& out, LogMsg& msg) override
        {
            out << LogLevel::toString(msg._level);
        }
    };
    class TimeFormatItem : public FormatItem
    {
        public:
        TimeFormatItem(const std::string& format):_format(format)
        {}
        void Format(std::ostream& out, LogMsg& msg) override
        {
            struct tm local_time;
            localtime_r(&msg._time,&local_time);
            char time[50] = {0};
            strftime(time,sizeof(time),_format.c_str(),&local_time);
            out << time;
        }
        private:
            std::string _format;
    }; 
    class FileFormatItem : public FormatItem
    {
        public:
        void Format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._filename;
        }
    };
    class LineFormatItem : public FormatItem
    {
        public:
        void Format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._line;
        }
    }; 
    class ThreadFormatItem : public FormatItem
    {
        public:
        void Format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._tid;
        }
    };
    class LoggerFormatItem : public FormatItem
    {
        public:
        void Format(std::ostream& out, LogMsg& msg) override
        {
            out << msg._logger;
        }
    };
    class TabFormatItem : public FormatItem
    {
        public:
        void Format(std::ostream& out, LogMsg& msg) override
        {
            out << "\t";
        }
    };
    class NLineFormatItem : public FormatItem
    {
        public:
        void Format(std::ostream& out, LogMsg& msg) override
        {
            out << "\n";
        }
    };
   class OtherFormatItem : public FormatItem
    {
        public:
        OtherFormatItem(const std::string& str):_str(str)
        {}
        void Format(std::ostream& out, LogMsg& msg) override
        {
            out << _str;
        }
        private:
            std::string _str;
    }; 
    class Formatter{
        public:
            using ptr = std::shared_ptr<Formatter>;
            Formatter(const std::string& pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"):_pattern(pattern)
            {
                assert(parsePattern());
            }
            void format(std::ostream &out,LogMsg log)
            {
                for(auto& item : _items)
                {
                    item->Format(out,log);
                }
            }
            std::string format(LogMsg log)
            {
                std::stringstream ss;
                format(ss,log);
                return ss.str();
            }
            bool parsePattern()
            {
                int pos = 0;
                std::vector<std::pair<std::string,std::string>> items;

                while(pos < _pattern.size())
                {
                    std::string key,val;

                    if(pos + 1 < _pattern.size() && _pattern[pos] == '%' && _pattern[pos+1] == '%')
                    {
                        val += _pattern[pos];
                        pos+=2;
                    }
                    else if(_pattern[pos] == '%')
                    {
                        //std::cout <<"11112222"<<std::endl;
                        pos++;
                        if(pos >= _pattern.size())
                        {
                            std::cout << "pattern err : %后无格式化字符" << std::endl;
                            return false;

                        }
                        key+=_pattern[pos];
                        pos++;
                        if(pos < _pattern.size() && _pattern[pos] == '{')
                        {

                            while(++pos < _pattern.size() && _pattern[pos] != '}')
                            {
                                val += _pattern[pos];
                            }
                            if(pos >=_pattern.size())
                            {
                                std::cout <<"pattern err : 无}" << std::endl;
                                return false;
                            }
                            pos++;

                        }
                    }
                    else
                    {
                        while(pos < _pattern.size() && _pattern[pos] != '%')
                        {
                            val += _pattern[pos];
                            pos++;
                        }
                    }

                    items.push_back({key,val});

                }
                for(auto& item : items)
                {
                    //std::cout << item.first<<" " << item.second << std::endl;
                    _items.push_back(creatitem(item.first,item.second));
                }
                return true;
            }
        private:
            FormatItem::ptr creatitem(const std::string &key, const std::string &val)
            {

                if(key == "d") return std::make_shared<TimeFormatItem>(val);
                else if (key == "t") return std::make_shared<ThreadFormatItem>();
                else if (key == "c") return std::make_shared<LoggerFormatItem>();
                else if (key == "f") return std::make_shared<FileFormatItem>();
                else if (key == "l") return std::make_shared<LineFormatItem>();
                else if (key == "p") return std::make_shared<LevelFormatItem>();
                else if (key == "T") return std::make_shared<TabFormatItem>();
                else if (key == "m") return std::make_shared<MsgFormatItem>();
                else if (key == "n") return std::make_shared<NLineFormatItem>();
                else if (key.size()) 
                {
                    std::cout << "not find %"<<key<<std::endl;
                    abort();
                }
                else return std::make_shared<OtherFormatItem>(val);
            }
            std::string _pattern;
            std::vector<FormatItem::ptr> _items;
    };
}

#endif